// Package service internal/service/menu_service.go
package service

import (
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/jinzhu/copier"
	"gozrd-admin-api/internal/entity/dto"
	"gozrd-admin-api/internal/entity/model"
	"gozrd-admin-api/internal/entity/vo"
	"gozrd-admin-api/internal/repository"
	"gozrd-admin-api/pkg/response"
	"time"
)

// IMenuService 菜单服务接口
type IMenuService interface {
	CreateSysMenu(c *gin.Context, menu dto.SysMenuDto)
	QuerySysMenuVoList(c *gin.Context)
	GetSysMenu(c *gin.Context, id int)
	UpdateSysMenu(c *gin.Context, menu dto.SysMenuDto)
	DeleteSysMenu(c *gin.Context, dto dto.SysMenuIdDto)
	GetSysMenuList(c *gin.Context, menuName string, menuStatus string)
}

// MenuServiceImpl 菜单服务实现
type MenuServiceImpl struct {
	menuRepository repository.IMenuRepository
	validator      *validator.Validate
}

// NewMenuService 创建菜单服务实例
func NewMenuService(menuRepo repository.IMenuRepository) IMenuService {
	return &MenuServiceImpl{
		menuRepository: menuRepo,
		validator:      validator.New(),
	}
}

// GetSysMenuList 查询菜单列表
func (s *MenuServiceImpl) GetSysMenuList(c *gin.Context, menuName string, menuStatus string) {
	// 调用Repository层获取数据
	menus, err := s.menuRepository.GetSysMenuList(menuName, menuStatus)
	if err != nil {
		response.Fail(c, response.ErrDatabase, "获取菜单列表失败："+err.Error())
		return
	}

	// 组织菜单树形结构
	menuTree := buildMenuTree(menus)

	response.Success(c, menuTree)
}

// 递归构建菜单树
func buildMenuTree(menus []model.Menu) []model.Menu {
	// 创建一个映射存储所有菜单，便于查找
	menuMap := make(map[int]*model.Menu)
	for i := range menus {
		menuMap[menus[i].ID] = &menus[i]
	}

	// 构建菜单树
	var rootMenus []model.Menu
	for i := range menus {
		menu := &menus[i]
		// 如果是顶级菜单
		if menu.ParentID == nil || *menu.ParentID == 0 {
			rootMenus = append(rootMenus, *menu)
		} else {
			// 找到父菜单，将当前菜单添加到父菜单的子菜单列表中
			if parent, exists := menuMap[*menu.ParentID]; exists {
				parent.Children = append(parent.Children, *menu)
			}
		}
	}

	return rootMenus
}

// DeleteSysMenu 删除菜单
func (s *MenuServiceImpl) DeleteSysMenu(c *gin.Context, dto dto.SysMenuIdDto) {
	// 验证DTO
	if err := s.validator.Struct(dto); err != nil {
		response.Fail(c, response.ErrParams, err.Error())
		return
	}

	// 调用Repository层
	err := s.menuRepository.DeleteSysMenu(int(dto.Id))
	if err != nil {
		if err == repository.MenuAssigned {
			response.Fail(c, response.BadRequest, "菜单已分配角色，无法删除")
			return
		}
		response.Fail(c, response.ErrDatabase, "删除菜单失败："+err.Error())
		return
	}

	response.Success(c, nil)
}

// UpdateSysMenu 修改菜单
func (s *MenuServiceImpl) UpdateSysMenu(c *gin.Context, menuDTO dto.SysMenuDto) {
	// 验证DTO
	if err := s.validator.Struct(menuDTO); err != nil {
		response.Fail(c, response.ErrParams, err.Error())
		return
	}

	// DTO转换为领域模型
	var menu model.Menu
	if err := copier.Copy(&menu, &menuDTO); err != nil {
		response.Fail(c, response.ErrParams, "数据转换失败: "+err.Error())
		return
	}

	// 处理ParentID
	parentID := menuDTO.ParentID
	if menuDTO.MenuType == 1 { // 目录类型
		menu.ParentID = nil
	} else {
		menu.ParentID = parentID
	}

	// 调用Repository层
	updatedMenu, err := s.menuRepository.UpdateSysMenu(menu)
	if err != nil {
		response.Fail(c, response.ErrDatabase, "更新菜单失败："+err.Error())
		return
	}

	// 转换为VO并返回
	var menuVO vo.SysMenuVO
	if err := copier.Copy(&menuVO, &updatedMenu); err != nil {
		response.Fail(c, response.ServerError, "数据转换失败")
		return
	}

	response.Success(c, menuVO)
}

// GetSysMenu 根据id查询菜单
func (s *MenuServiceImpl) GetSysMenu(c *gin.Context, id int) {
	// 调用Repository层
	menu, err := s.menuRepository.GetSysMenu(id)
	if err != nil {
		response.Fail(c, response.ErrDatabase, "获取菜单详情失败："+err.Error())
		return
	}

	// 转换为VO
	var menuVO vo.SysMenuVO
	if err := copier.Copy(&menuVO, &menu); err != nil {
		response.Fail(c, response.ServerError, "数据转换失败")
		return
	}

	response.Success(c, menuVO)
}

// QuerySysMenuVoList 查询下拉选项列表
func (s *MenuServiceImpl) QuerySysMenuVoList(c *gin.Context) {
	// 调用Repository获取完整菜单列表
	menus, err := s.menuRepository.GetSysMenuList("", "")
	if err != nil {
		response.Fail(c, response.ErrDatabase, "获取菜单列表失败："+err.Error())
		return
	}

	// 转换为下拉选项VO
	var menuVOs []vo.SysMenuVo
	for _, menu := range menus {
		var parentId int
		if menu.ParentID != nil {
			parentId = *menu.ParentID
		}

		menuVO := vo.SysMenuVo{
			Id:       int(menu.ID),
			ParentId: parentId,
			Label:    menu.MenuName,
		}
		menuVOs = append(menuVOs, menuVO)
	}

	response.Success(c, menuVOs)
}

// CreateSysMenu 创建菜单
func (s *MenuServiceImpl) CreateSysMenu(c *gin.Context, menuDTO dto.SysMenuDto) {
	// 验证DTO
	if err := s.validator.Struct(menuDTO); err != nil {
		response.Fail(c, response.ErrParams, err.Error())
		return
	}

	// DTO转换为领域模型
	var menu model.Menu
	if err := copier.Copy(&menu, &menuDTO); err != nil {
		response.Fail(c, response.ErrParams, "数据转换失败: "+err.Error())
		return
	}

	// 处理ParentID
	parentID := menuDTO.ParentID
	if menuDTO.MenuType == 1 { // 目录类型
		menu.ParentID = nil
	} else {
		menu.ParentID = parentID
	}

	// 设置创建时间
	now := time.Now()
	menu.CreateTime = &now

	// 调用Repository层
	err := s.menuRepository.CreateSysMenu(menu)
	if err != nil {
		if err == repository.MenuExist {
			response.Fail(c, response.BadRequest, "菜单名称已存在")
			return
		}
		response.Fail(c, response.ErrDatabase, "创建菜单失败："+err.Error())
		return
	}

	response.SuccessWithMessage(c, "创建成功", nil)
}
